/**
 * Copyright (c) Tiny Technologies, Inc. All rights reserved.
 * Licensed under the LGPL or a commercial license.
 * For LGPL see License.txt in the project root for license information.
 * For commercial licenses see https://www.tiny.cloud/
 *
 * Version: 5.0.16 (2019-09-24)
 */
(function (domGlobals) {
    'use strict';

    var global = tinymce.util.Tools.resolve('tinymce.PluginManager');

    var global$1 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');

    var window = {};
    var global$2 = window;
    var _self = typeof window !== 'undefined' ? window : typeof WorkerGlobalScope !== 'undefined' && domGlobals.self instanceof WorkerGlobalScope ? domGlobals.self : {};
    var Prism = function () {
        var lang = /\blang(?:uage)?-(?!\*)(\w+)\b/i;
        var _ = _self.Prism = {
            util: {
                encode: function (tokens) {
                    if (tokens instanceof Token) {
                        return new Token(tokens.type, _.util.encode(tokens.content), tokens.alias);
                    } else if (_.util.type(tokens) === 'Array') {
                        return tokens.map(_.util.encode);
                    } else {
                        return tokens.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/\u00a0/g, ' ');
                    }
                },
                type: function (o) {
                    return Object.prototype.toString.call(o).match(/\[object (\w+)\]/)[1];
                },
                clone: function (o) {
                    var type = _.util.type(o);
                    switch (type) {
                        case 'Object':
                            var clone = {};
                            for (var key in o) {
                                if (o.hasOwnProperty(key)) {
                                    clone[key] = _.util.clone(o[key]);
                                }
                            }
                            return clone;
                        case 'Array':
                            return o.map && o.map(function (v) {
                                return _.util.clone(v);
                            });
                    }
                    return o;
                }
            },
            languages: {
                extend: function (id, redef) {
                    var lang = _.util.clone(_.languages[id]);
                    for (var key in redef) {
                        lang[key] = redef[key];
                    }
                    return lang;
                },
                insertBefore: function (inside, before, insert, root) {
                    root = root || _.languages;
                    var grammar = root[inside];
                    if (arguments.length === 2) {
                        insert = arguments[1];
                        for (var newToken in insert) {
                            if (insert.hasOwnProperty(newToken)) {
                                grammar[newToken] = insert[newToken];
                            }
                        }
                        return grammar;
                    }
                    var ret = {};
                    for (var token in grammar) {
                        if (grammar.hasOwnProperty(token)) {
                            if (token === before) {
                                for (var newToken in insert) {
                                    if (insert.hasOwnProperty(newToken)) {
                                        ret[newToken] = insert[newToken];
                                    }
                                }
                            }
                            ret[token] = grammar[token];
                        }
                    }
                    _.languages.DFS(_.languages, function (key, value) {
                        if (value === root[inside] && key !== inside) {
                            this[key] = ret;
                        }
                    });
                    return root[inside] = ret;
                },
                DFS: function (o, callback, type) {
                    for (var i in o) {
                        if (o.hasOwnProperty(i)) {
                            callback.call(o, i, o[i], type || i);
                            if (_.util.type(o[i]) === 'Object') {
                                _.languages.DFS(o[i], callback);
                            } else if (_.util.type(o[i]) === 'Array') {
                                _.languages.DFS(o[i], callback, i);
                            }
                        }
                    }
                }
            },
            plugins: {},
            highlightAll: function (async, callback) {
                var elements = domGlobals.document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code');
                for (var i = 0, element = void 0; element = elements[i++];) {
                    _.highlightElement(element, async === true, callback);
                }
            },
            highlightElement: function (element, async, callback) {
                var language, grammar, parent = element;
                while (parent && !lang.test(parent.className)) {
                    parent = parent.parentNode;
                }
                if (parent) {
                    language = (parent.className.match(lang) || [
                        ,
                        ''
                    ])[1];
                    grammar = _.languages[language];
                }
                element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
                parent = element.parentNode;
                if (/pre/i.test(parent.nodeName)) {
                    parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
                }
                var code = element.textContent;
                var env = {
                    element: element,
                    language: language,
                    grammar: grammar,
                    code: code
                };
                if (!code || !grammar) {
                    _.hooks.run('complete', env);
                    return;
                }
                _.hooks.run('before-highlight', env);
                if (async && _self.Worker) {
                    var worker = new domGlobals.Worker(_.filename);
                    worker.onmessage = function (evt) {
                        env.highlightedCode = evt.data;
                        _.hooks.run('before-insert', env);
                        env.element.innerHTML = env.highlightedCode;
                        if (callback) {
                            callback.call(env.element);
                        }
                        _.hooks.run('after-highlight', env);
                        _.hooks.run('complete', env);
                    };
                    worker.postMessage(JSON.stringify({
                        language: env.language,
                        code: env.code,
                        immediateClose: true
                    }));
                } else {
                    env.highlightedCode = _.highlight(env.code, env.grammar, env.language);
                    _.hooks.run('before-insert', env);
                    env.element.innerHTML = env.highlightedCode;
                    if (callback) {
                        callback.call(element);
                    }
                    _.hooks.run('after-highlight', env);
                    _.hooks.run('complete', env);
                }
            },
            highlight: function (text, grammar, language) {
                var tokens = _.tokenize(text, grammar);
                return Token.stringify(_.util.encode(tokens), language);
            },
            tokenize: function (text, grammar, language) {
                var Token = _.Token;
                var strarr = [text];
                var rest = grammar.rest;
                if (rest) {
                    for (var token in rest) {
                        grammar[token] = rest[token];
                    }
                    delete grammar.rest;
                }
                tokenloop:
                    for (var token in grammar) {
                        if (!grammar.hasOwnProperty(token) || !grammar[token]) {
                            continue;
                        }
                        var patterns = grammar[token];
                        patterns = _.util.type(patterns) === 'Array' ? patterns : [patterns];
                        for (var j = 0; j < patterns.length; ++j) {
                            var pattern = patterns[j];
                            var inside = pattern.inside;
                            var lookbehind = !!pattern.lookbehind;
                            var lookbehindLength = 0;
                            var alias = pattern.alias;
                            pattern = pattern.pattern || pattern;
                            for (var i = 0; i < strarr.length; i++) {
                                var str = strarr[i];
                                if (strarr.length > text.length) {
                                    break tokenloop;
                                }
                                if (str instanceof Token) {
                                    continue;
                                }
                                pattern.lastIndex = 0;
                                var match = pattern.exec(str);
                                if (match) {
                                    if (lookbehind) {
                                        lookbehindLength = match[1].length;
                                    }
                                    var from = match.index - 1 + lookbehindLength;
                                    match = match[0].slice(lookbehindLength);
                                    var len = match.length, to = from + len, before = str.slice(0, from + 1),
                                        after = str.slice(to + 1);
                                    var args = [
                                        i,
                                        1
                                    ];
                                    if (before) {
                                        args.push(before);
                                    }
                                    var wrapped = new Token(token, inside ? _.tokenize(match, inside) : match, alias);
                                    args.push(wrapped);
                                    if (after) {
                                        args.push(after);
                                    }
                                    Array.prototype.splice.apply(strarr, args);
                                }
                            }
                        }
                    }
                return strarr;
            },
            hooks: {
                all: {},
                add: function (name, callback) {
                    var hooks = _.hooks.all;
                    hooks[name] = hooks[name] || [];
                    hooks[name].push(callback);
                },
                run: function (name, env) {
                    var callbacks = _.hooks.all[name];
                    if (!callbacks || !callbacks.length) {
                        return;
                    }
                    for (var i = 0, callback = void 0; callback = callbacks[i++];) {
                        callback(env);
                    }
                }
            }
        };
        var Token = _.Token = function (type, content, alias) {
            this.type = type;
            this.content = content;
            this.alias = alias;
        };
        Token.stringify = function (o, language, parent) {
            if (typeof o === 'string') {
                return o;
            }
            if (_.util.type(o) === 'Array') {
                return o.map(function (element) {
                    return Token.stringify(element, language, o);
                }).join('');
            }
            var env = {
                type: o.type,
                content: Token.stringify(o.content, language, parent),
                tag: 'span',
                classes: [
                    'token',
                    o.type
                ],
                attributes: {},
                language: language,
                parent: parent
            };
            if (env.type === 'comment') {
                env.attributes.spellcheck = 'true';
            }
            if (o.alias) {
                var aliases = _.util.type(o.alias) === 'Array' ? o.alias : [o.alias];
                Array.prototype.push.apply(env.classes, aliases);
            }
            _.hooks.run('wrap', env);
            var attributes = '';
            for (var name in env.attributes) {
                attributes += (attributes ? ' ' : '') + name + '="' + (env.attributes[name] || '') + '"';
            }
            return '<' + env.tag + ' class="' + env.classes.join(' ') + '" ' + attributes + '>' + env.content + '</' + env.tag + '>';
        };
        if (!_self.document) {
            if (!_self.addEventListener) {
                return _self.Prism;
            }
            _self.addEventListener('message', function (evt) {
                var message = JSON.parse(evt.data), lang = message.language, code = message.code,
                    immediateClose = message.immediateClose;
                _self.postMessage(_.highlight(code, _.languages[lang], lang));
                if (immediateClose) {
                    _self.close();
                }
            }, false);
            return _self.Prism;
        }
    }();
    if (typeof global$2 !== 'undefined') {
        global$2.Prism = Prism;
    }
    Prism.languages.markup = {
        comment: /<!--[\w\W]*?-->/,
        prolog: /<\?[\w\W]+?\?>/,
        doctype: /<!DOCTYPE[\w\W]+?>/,
        cdata: /<!\[CDATA\[[\w\W]*?]]>/i,
        tag: {
            pattern: /<\/?[^\s>\/=.]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,
            inside: {
                'tag': {
                    pattern: /^<\/?[^\s>\/]+/i,
                    inside: {
                        punctuation: /^<\/?/,
                        namespace: /^[^\s>\/:]+:/
                    }
                },
                'attr-value': {
                    pattern: /=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,
                    inside: {punctuation: /[=>"']/}
                },
                'punctuation': /\/?>/,
                'attr-name': {
                    pattern: /[^\s>\/]+/,
                    inside: {namespace: /^[^\s>\/:]+:/}
                }
            }
        },
        entity: /&#?[\da-z]{1,8};/i
    };
    Prism.hooks.add('wrap', function (env) {
        if (env.type === 'entity') {
            env.attributes.title = env.content.replace(/&amp;/, '&');
        }
    });
    Prism.languages.xml = Prism.languages.markup;
    Prism.languages.html = Prism.languages.markup;
    Prism.languages.mathml = Prism.languages.markup;
    Prism.languages.svg = Prism.languages.markup;
    Prism.languages.css = {
        comment: /\/\*[\w\W]*?\*\//,
        atrule: {
            pattern: /@[\w-]+?.*?(;|(?=\s*\{))/i,
            inside: {rule: /@[\w-]+/}
        },
        url: /url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,
        selector: /[^\{\}\s][^\{\};]*?(?=\s*\{)/,
        string: /("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,
        property: /(\b|\B)[\w-]+(?=\s*:)/i,
        important: /\B!important\b/i,
        function: /[-a-z0-9]+(?=\()/i,
        punctuation: /[(){};:]/
    };
    Prism.languages.css.atrule.inside.rest = Prism.util.clone(Prism.languages.css);
    if (Prism.languages.markup) {
        Prism.languages.insertBefore('markup', 'tag', {
            style: {
                pattern: /<style[\w\W]*?>[\w\W]*?<\/style>/i,
                inside: {
                    tag: {
                        pattern: /<style[\w\W]*?>|<\/style>/i,
                        inside: Prism.languages.markup.tag.inside
                    },
                    rest: Prism.languages.css
                },
                alias: 'language-css'
            }
        });
        Prism.languages.insertBefore('inside', 'attr-value', {
            'style-attr': {
                pattern: /\s*style=("|').*?\1/i,
                inside: {
                    'attr-name': {
                        pattern: /^\s*style/i,
                        inside: Prism.languages.markup.tag.inside
                    },
                    'punctuation': /^\s*=\s*['"]|['"]\s*$/,
                    'attr-value': {
                        pattern: /.+/i,
                        inside: Prism.languages.css
                    }
                },
                alias: 'language-css'
            }
        }, Prism.languages.markup.tag);
    }
    Prism.languages.clike = {
        'comment': [
            {
                pattern: /(^|[^\\])\/\*[\w\W]*?\*\//,
                lookbehind: true
            },
            {
                pattern: /(^|[^\\:])\/\/.*/,
                lookbehind: true
            }
        ],
        'string': /(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
        'class-name': {
            pattern: /((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,
            lookbehind: true,
            inside: {punctuation: /(\.|\\)/}
        },
        'keyword': /\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,
        'boolean': /\b(true|false)\b/,
        'function': /[a-z0-9_]+(?=\()/i,
        'number': /\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,
        'operator': /--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,
        'punctuation': /[{}[\];(),.:]/
    };
    Prism.languages.javascript = Prism.languages.extend('clike', {
        keyword: /\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/,
        number: /\b-?(0x[\dA-Fa-f]+|0b[01]+|0o[0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/,
        function: /[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*(?=\()/i
    });
    Prism.languages.insertBefore('javascript', 'keyword', {
        regex: {
            pattern: /(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,
            lookbehind: true
        }
    });
    Prism.languages.insertBefore('javascript', 'class-name', {
        'template-string': {
            pattern: /`(?:\\`|\\?[^`])*`/,
            inside: {
                interpolation: {
                    pattern: /\$\{[^}]+\}/,
                    inside: {
                        'interpolation-punctuation': {
                            pattern: /^\$\{|\}$/,
                            alias: 'punctuation'
                        },
                        'rest': Prism.languages.javascript
                    }
                },
                string: /[\s\S]+/
            }
        }
    });
    if (Prism.languages.markup) {
        Prism.languages.insertBefore('markup', 'tag', {
            script: {
                pattern: /<script[\w\W]*?>[\w\W]*?<\/script>/i,
                inside: {
                    tag: {
                        pattern: /<script[\w\W]*?>|<\/script>/i,
                        inside: Prism.languages.markup.tag.inside
                    },
                    rest: Prism.languages.javascript
                },
                alias: 'language-javascript'
            }
        });
    }
    Prism.languages.js = Prism.languages.javascript;
    Prism.languages.c = Prism.languages.extend('clike', {
        keyword: /\b(asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/,
        operator: /\-[>-]?|\+\+?|!=?|<<?=?|>>?=?|==?|&&?|\|?\||[~^%?*\/]/,
        number: /\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)[ful]*\b/i
    });
    Prism.languages.insertBefore('c', 'string', {
        macro: {
            pattern: /(^\s*)#\s*[a-z]+([^\r\n\\]|\\.|\\(?:\r\n?|\n))*/im,
            lookbehind: true,
            alias: 'property',
            inside: {
                string: {
                    pattern: /(#\s*include\s*)(<.+?>|("|')(\\?.)+?\3)/,
                    lookbehind: true
                }
            }
        }
    });
    delete Prism.languages.c['class-name'];
    delete Prism.languages.c.boolean;
    Prism.languages.csharp = Prism.languages.extend('clike', {
        keyword: /\b(abstract|as|async|await|base|bool|break|byte|case|catch|char|checked|class|const|continue|decimal|default|delegate|do|double|else|enum|event|explicit|extern|false|finally|fixed|float|for|foreach|goto|if|implicit|in|int|interface|internal|is|lock|long|namespace|new|null|object|operator|out|override|params|private|protected|public|readonly|ref|return|sbyte|sealed|short|sizeof|stackalloc|static|string|struct|switch|this|throw|true|try|typeof|uint|ulong|unchecked|unsafe|ushort|using|virtual|void|volatile|while|add|alias|ascending|async|await|descending|dynamic|from|get|global|group|into|join|let|orderby|partial|remove|select|set|value|var|where|yield)\b/,
        string: [
            /@("|')(\1\1|\\\1|\\?(?!\1)[\s\S])*\1/,
            /("|')(\\?.)*?\1/
        ],
        number: /\b-?(0x[\da-f]+|\d*\.?\d+)\b/i
    });
    Prism.languages.insertBefore('csharp', 'keyword', {
        preprocessor: {
            pattern: /(^\s*)#.*/m,
            lookbehind: true
        }
    });
    Prism.languages.cpp = Prism.languages.extend('c', {
        keyword: /\b(alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|class|compl|const|constexpr|const_cast|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|float|for|friend|goto|if|inline|int|long|mutable|namespace|new|noexcept|nullptr|operator|private|protected|public|register|reinterpret_cast|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,
        boolean: /\b(true|false)\b/,
        operator: /[-+]{1,2}|!=?|<{1,2}=?|>{1,2}=?|\->|:{1,2}|={1,2}|\^|~|%|&{1,2}|\|?\||\?|\*|\/|\b(and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/
    });
    Prism.languages.insertBefore('cpp', 'keyword', {
        'class-name': {
            pattern: /(class\s+)[a-z0-9_]+/i,
            lookbehind: true
        }
    });
    Prism.languages.java = Prism.languages.extend('clike', {
        keyword: /\b(abstract|continue|for|new|switch|assert|default|goto|package|synchronized|boolean|do|if|private|this|break|double|implements|protected|throw|byte|else|import|public|throws|case|enum|instanceof|return|transient|catch|extends|int|short|try|char|final|interface|static|void|class|finally|long|strictfp|volatile|const|float|native|super|while)\b/,
        number: /\b0b[01]+\b|\b0x[\da-f]*\.?[\da-fp\-]+\b|\b\d*\.?\d+(?:e[+-]?\d+)?[df]?\b/i,
        operator: {
            pattern: /(^|[^.])(?:\+[+=]?|-[-=]?|!=?|<<?=?|>>?>?=?|==?|&[&=]?|\|[|=]?|\*=?|\/=?|%=?|\^=?|[?:~])/m,
            lookbehind: true
        }
    });
    Prism.languages.php = Prism.languages.extend('clike', {
        keyword: /\b(and|or|xor|array|as|break|case|cfunction|class|const|continue|declare|default|die|do|else|elseif|enddeclare|endfor|endforeach|endif|endswitch|endwhile|extends|for|foreach|function|include|include_once|global|if|new|return|static|switch|use|require|require_once|var|while|abstract|interface|public|implements|private|protected|parent|throw|null|echo|print|trait|namespace|final|yield|goto|instanceof|finally|try|catch)\b/i,
        constant: /\b[A-Z0-9_]{2,}\b/,
        comment: {
            pattern: /(^|[^\\])(?:\/\*[\w\W]*?\*\/|\/\/.*)/,
            lookbehind: true
        }
    });
    Prism.languages.insertBefore('php', 'class-name', {
        'shell-comment': {
            pattern: /(^|[^\\])#.*/,
            lookbehind: true,
            alias: 'comment'
        }
    });
    Prism.languages.insertBefore('php', 'keyword', {
        delimiter: /\?>|<\?(?:php)?/i,
        variable: /\$\w+\b/i,
        package: {
            pattern: /(\\|namespace\s+|use\s+)[\w\\]+/,
            lookbehind: true,
            inside: {punctuation: /\\/}
        }
    });
    Prism.languages.insertBefore('php', 'operator', {
        property: {
            pattern: /(->)[\w]+/,
            lookbehind: true
        }
    });
    if (Prism.languages.markup) {
        Prism.hooks.add('before-highlight', function (env) {
            if (env.language !== 'php') {
                return;
            }
            env.tokenStack = [];
            env.backupCode = env.code;
            env.code = env.code.replace(/(?:<\?php|<\?)[\w\W]*?(?:\?>)/ig, function (match) {
                env.tokenStack.push(match);
                return '{{{PHP' + env.tokenStack.length + '}}}';
            });
        });
        Prism.hooks.add('before-insert', function (env) {
            if (env.language === 'php') {
                env.code = env.backupCode;
                delete env.backupCode;
            }
        });
        Prism.hooks.add('after-highlight', function (env) {
            if (env.language !== 'php') {
                return;
            }
            for (var i = 0, t = void 0; t = env.tokenStack[i]; i++) {
                env.highlightedCode = env.highlightedCode.replace('{{{PHP' + (i + 1) + '}}}', Prism.highlight(t, env.grammar, 'php').replace(/\$/g, '$$$$'));
            }
            env.element.innerHTML = env.highlightedCode;
        });
        Prism.hooks.add('wrap', function (env) {
            if (env.language === 'php' && env.type === 'markup') {
                env.content = env.content.replace(/(\{\{\{PHP[0-9]+\}\}\})/g, '<span class="token php">$1</span>');
            }
        });
        Prism.languages.insertBefore('php', 'comment', {
            markup: {
                pattern: /<[^?]\/?(.*?)>/,
                inside: Prism.languages.markup
            },
            php: /\{\{\{PHP[0-9]+\}\}\}/
        });
    }
    Prism.languages.python = {
        'comment': {
            pattern: /(^|[^\\])#.*/,
            lookbehind: true
        },
        'string': /"""[\s\S]+?"""|'''[\s\S]+?'''|("|')(?:\\?.)*?\1/,
        'function': {
            pattern: /((?:^|\s)def[ \t]+)[a-zA-Z_][a-zA-Z0-9_]*(?=\()/g,
            lookbehind: true
        },
        'class-name': {
            pattern: /(\bclass\s+)[a-z0-9_]+/i,
            lookbehind: true
        },
        'keyword': /\b(?:as|assert|async|await|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|pass|print|raise|return|try|while|with|yield)\b/,
        'boolean': /\b(?:True|False)\b/,
        'number': /\b-?(?:0[bo])?(?:(?:\d|0x[\da-f])[\da-f]*\.?\d*|\.\d+)(?:e[+-]?\d+)?j?\b/i,
        'operator': /[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]|\b(?:or|and|not)\b/,
        'punctuation': /[{}[\];(),.:]/
    };
    (function (Prism) {
        Prism.languages.ruby = Prism.languages.extend('clike', {
            comment: /#(?!\{[^\r\n]*?\}).*/,
            keyword: /\b(alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|false|for|if|in|module|new|next|nil|not|or|raise|redo|require|rescue|retry|return|self|super|then|throw|true|undef|unless|until|when|while|yield)\b/
        });
        var interpolation = {
            pattern: /#\{[^}]+\}/,
            inside: {
                delimiter: {
                    pattern: /^#\{|\}$/,
                    alias: 'tag'
                },
                rest: Prism.util.clone(Prism.languages.ruby)
            }
        };
        Prism.languages.insertBefore('ruby', 'keyword', {
            regex: [
                {
                    pattern: /%r([^a-zA-Z0-9\s\{\(\[<])(?:[^\\]|\\[\s\S])*?\1[gim]{0,3}/,
                    inside: {interpolation: interpolation}
                },
                {
                    pattern: /%r\((?:[^()\\]|\\[\s\S])*\)[gim]{0,3}/,
                    inside: {interpolation: interpolation}
                },
                {
                    pattern: /%r\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}[gim]{0,3}/,
                    inside: {interpolation: interpolation}
                },
                {
                    pattern: /%r\[(?:[^\[\]\\]|\\[\s\S])*\][gim]{0,3}/,
                    inside: {interpolation: interpolation}
                },
                {
                    pattern: /%r<(?:[^<>\\]|\\[\s\S])*>[gim]{0,3}/,
                    inside: {interpolation: interpolation}
                },
                {
                    pattern: /(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/,
                    lookbehind: true
                }
            ],
            variable: /[@$]+[a-zA-Z_][a-zA-Z_0-9]*(?:[?!]|\b)/,
            symbol: /:[a-zA-Z_][a-zA-Z_0-9]*(?:[?!]|\b)/
        });
        Prism.languages.insertBefore('ruby', 'number', {
            builtin: /\b(Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Stat|File|Fixnum|Fload|Hash|Integer|IO|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|String|Struct|TMS|Symbol|ThreadGroup|Thread|Time|TrueClass)\b/,
            constant: /\b[A-Z][a-zA-Z_0-9]*(?:[?!]|\b)/
        });
        Prism.languages.ruby.string = [
            {
                pattern: /%[qQiIwWxs]?([^a-zA-Z0-9\s\{\(\[<])(?:[^\\]|\\[\s\S])*?\1/,
                inside: {interpolation: interpolation}
            },
            {
                pattern: /%[qQiIwWxs]?\((?:[^()\\]|\\[\s\S])*\)/,
                inside: {interpolation: interpolation}
            },
            {
                pattern: /%[qQiIwWxs]?\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}/,
                inside: {interpolation: interpolation}
            },
            {
                pattern: /%[qQiIwWxs]?\[(?:[^\[\]\\]|\\[\s\S])*\]/,
                inside: {interpolation: interpolation}
            },
            {
                pattern: /%[qQiIwWxs]?<(?:[^<>\\]|\\[\s\S])*>/,
                inside: {interpolation: interpolation}
            },
            {
                pattern: /("|')(#\{[^}]+\}|\\(?:\r?\n|\r)|\\?.)*?\1/,
                inside: {interpolation: interpolation}
            }
        ];
    }(Prism));

    function isCodeSample(elm) {
        return elm && elm.nodeName === 'PRE' && elm.className.indexOf('language-') !== -1;
    }

    function trimArg(predicateFn) {
        return function (arg1, arg2) {
            return predicateFn(arg2);
        };
    }

    var Utils = {
        isCodeSample: isCodeSample,
        trimArg: trimArg
    };

    var noop = function () {
    };
    var constant = function (value) {
        return function () {
            return value;
        };
    };
    var never = constant(false);
    var always = constant(true);

    var none = function () {
        return NONE;
    };
    var NONE = function () {
        var eq = function (o) {
            return o.isNone();
        };
        var call = function (thunk) {
            return thunk();
        };
        var id = function (n) {
            return n;
        };
        var me = {
            fold: function (n, s) {
                return n();
            },
            is: never,
            isSome: never,
            isNone: always,
            getOr: id,
            getOrThunk: call,
            getOrDie: function (msg) {
                throw new Error(msg || 'error: getOrDie called on none.');
            },
            getOrNull: constant(null),
            getOrUndefined: constant(undefined),
            or: id,
            orThunk: call,
            map: none,
            each: noop,
            bind: none,
            exists: never,
            forall: always,
            filter: none,
            equals: eq,
            equals_: eq,
            toArray: function () {
                return [];
            },
            toString: constant('none()')
        };
        if (Object.freeze) {
            Object.freeze(me);
        }
        return me;
    }();
    var some = function (a) {
        var constant_a = constant(a);
        var self = function () {
            return me;
        };
        var bind = function (f) {
            return f(a);
        };
        var me = {
            fold: function (n, s) {
                return s(a);
            },
            is: function (v) {
                return a === v;
            },
            isSome: always,
            isNone: never,
            getOr: constant_a,
            getOrThunk: constant_a,
            getOrDie: constant_a,
            getOrNull: constant_a,
            getOrUndefined: constant_a,
            or: self,
            orThunk: self,
            map: function (f) {
                return some(f(a));
            },
            each: function (f) {
                f(a);
            },
            bind: bind,
            exists: bind,
            forall: bind,
            filter: function (f) {
                return f(a) ? me : NONE;
            },
            toArray: function () {
                return [a];
            },
            toString: function () {
                return 'some(' + a + ')';
            },
            equals: function (o) {
                return o.is(a);
            },
            equals_: function (o, elementEq) {
                return o.fold(never, function (b) {
                    return elementEq(a, b);
                });
            }
        };
        return me;
    };
    var from = function (value) {
        return value === null || value === undefined ? NONE : some(value);
    };
    var Option = {
        some: some,
        none: none,
        from: from
    };

    var getSelectedCodeSample = function (editor) {
        var node = editor.selection ? editor.selection.getNode() : null;
        if (Utils.isCodeSample(node)) {
            return Option.some(node);
        }
        return Option.none();
    };
    var insertCodeSample = function (editor, language, code) {
        editor.undoManager.transact(function () {
            var node = getSelectedCodeSample(editor);
            code = global$1.DOM.encode(code);
            return node.fold(function () {
                editor.insertContent('<pre id="__new" class="language-' + language + '">' + code + '</pre>');
                editor.selection.select(editor.$('#__new').removeAttr('id')[0]);
            }, function (n) {
                editor.dom.setAttrib(n, 'class', 'language-' + language);
                n.innerHTML = code;
                Prism.highlightElement(n);
                editor.selection.select(n);
            });
        });
    };
    var getCurrentCode = function (editor) {
        var node = getSelectedCodeSample(editor);
        return node.fold(function () {
            return '';
        }, function (n) {
            return n.textContent;
        });
    };
    var CodeSample = {
        getSelectedCodeSample: getSelectedCodeSample,
        insertCodeSample: insertCodeSample,
        getCurrentCode: getCurrentCode
    };

    var getLanguages = function (editor) {
        return editor.settings.codesample_languages;
    };
    var Settings = {getLanguages: getLanguages};

    var getLanguages$1 = function (editor) {
        var defaultLanguages = [
            {
                text: 'HTML/XML',
                value: 'markup'
            },
            {
                text: 'JavaScript',
                value: 'javascript'
            },
            {
                text: 'CSS',
                value: 'css'
            },
            {
                text: 'PHP',
                value: 'php'
            },
            {
                text: 'Ruby',
                value: 'ruby'
            },
            {
                text: 'Python',
                value: 'python'
            },
            {
                text: 'Java',
                value: 'java'
            },
            {
                text: 'C',
                value: 'c'
            },
            {
                text: 'C#',
                value: 'csharp'
            },
            {
                text: 'C++',
                value: 'cpp'
            }
        ];
        var customLanguages = Settings.getLanguages(editor);
        return customLanguages ? customLanguages : defaultLanguages;
    };
    var getCurrentLanguage = function (editor, fallback) {
        var node = CodeSample.getSelectedCodeSample(editor);
        return node.fold(function () {
            return fallback;
        }, function (n) {
            var matches = n.className.match(/language-(\w+)/);
            return matches ? matches[1] : fallback;
        });
    };
    var Languages = {
        getLanguages: getLanguages$1,
        getCurrentLanguage: getCurrentLanguage
    };

    var typeOf = function (x) {
        if (x === null) {
            return 'null';
        }
        var t = typeof x;
        if (t === 'object' && (Array.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'Array')) {
            return 'array';
        }
        if (t === 'object' && (String.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'String')) {
            return 'string';
        }
        return t;
    };
    var isType = function (type) {
        return function (value) {
            return typeOf(value) === type;
        };
    };
    var isFunction = isType('function');

    var nativeSlice = Array.prototype.slice;
    var head = function (xs) {
        return xs.length === 0 ? Option.none() : Option.some(xs[0]);
    };
    var from$1 = isFunction(Array.from) ? Array.from : function (x) {
        return nativeSlice.call(x);
    };

    var open = function (editor) {
        var languages = Languages.getLanguages(editor);
        var defaultLanguage = head(languages).fold(function () {
            return '';
        }, function (l) {
            return l.value;
        });
        var currentLanguage = Languages.getCurrentLanguage(editor, defaultLanguage);
        var currentCode = CodeSample.getCurrentCode(editor);
        editor.windowManager.open({
            title: 'Insert/Edit Code Sample',
            size: 'large',
            body: {
                type: 'panel',
                items: [
                    {
                        type: 'selectbox',
                        name: 'language',
                        label: 'Language',
                        items: languages
                    },
                    {
                        type: 'textarea',
                        name: 'code',
                        label: 'Code view'
                    }
                ]
            },
            buttons: [
                {
                    type: 'cancel',
                    name: 'cancel',
                    text: 'Cancel'
                },
                {
                    type: 'submit',
                    name: 'save',
                    text: 'Save',
                    primary: true
                }
            ],
            initialData: {
                language: currentLanguage,
                code: currentCode
            },
            onSubmit: function (api) {
                var data = api.getData();
                CodeSample.insertCodeSample(editor, data.language, data.code);
                api.close();
            }
        });
    };
    var Dialog = {open: open};

    var register = function (editor) {
        editor.addCommand('codesample', function () {
            var node = editor.selection.getNode();
            if (editor.selection.isCollapsed() || Utils.isCodeSample(node)) {
                Dialog.open(editor);
            } else {
                editor.formatter.toggle('code');
            }
        });
    };
    var Commands = {register: register};

    var setup = function (editor) {
        var $ = editor.$;
        editor.on('PreProcess', function (e) {
            $('pre[contenteditable=false]', e.node).filter(Utils.trimArg(Utils.isCodeSample)).each(function (idx, elm) {
                var $elm = $(elm), code = elm.textContent;
                $elm.attr('class', $.trim($elm.attr('class')));
                $elm.removeAttr('contentEditable');
                $elm.empty().append($('<code></code>').each(function () {
                    this.textContent = code;
                }));
            });
        });
        editor.on('SetContent', function () {
            var unprocessedCodeSamples = $('pre').filter(Utils.trimArg(Utils.isCodeSample)).filter(function (idx, elm) {
                return elm.contentEditable !== 'false';
            });
            if (unprocessedCodeSamples.length) {
                editor.undoManager.transact(function () {
                    unprocessedCodeSamples.each(function (idx, elm) {
                        $(elm).find('br').each(function (idx, elm) {
                            elm.parentNode.replaceChild(editor.getDoc().createTextNode('\n'), elm);
                        });
                        elm.contentEditable = 'false';
                        elm.innerHTML = editor.dom.encode(elm.textContent);
                        Prism.highlightElement(elm);
                        elm.className = $.trim(elm.className);
                    });
                });
            }
        });
    };
    var FilterContent = {setup: setup};

    var isCodeSampleSelection = function (editor) {
        var node = editor.selection.getStart();
        return editor.dom.is(node, 'pre.language-markup');
    };
    var register$1 = function (editor) {
        editor.ui.registry.addToggleButton('codesample', {
            icon: 'code-sample',
            tooltip: 'Insert/edit code sample',
            onAction: function () {
                return Dialog.open(editor);
            },
            onSetup: function (api) {
                var nodeChangeHandler = function () {
                    api.setActive(isCodeSampleSelection(editor));
                };
                editor.on('NodeChange', nodeChangeHandler);
                return function () {
                    return editor.off('NodeChange', nodeChangeHandler);
                };
            }
        });
        editor.ui.registry.addMenuItem('codesample', {
            text: 'Code sample...',
            icon: 'code-sample',
            onAction: function () {
                return Dialog.open(editor);
            }
        });
    };
    var Buttons = {register: register$1};

    function Plugin() {
        global.add('codesample', function (editor) {
            FilterContent.setup(editor);
            Buttons.register(editor);
            Commands.register(editor);
            editor.on('dblclick', function (ev) {
                if (Utils.isCodeSample(ev.target)) {
                    Dialog.open(editor);
                }
            });
        });
    }

    Plugin();

}(window));
